<!--
 * Copyright © 2023
 * @Author: zhangxiang
 * @Date: 2023-03-10 16:39:28
 * @LastEditors: zhangxiang
 * @LastEditTime: 2023-09-26 11:37:53
 * @Description: 单个微服务部署详情
 *
-->

<template>
  <div class="service-deployment-ctn">
    <div class="title">
      {{ microService.svcName }}
      <div v-if="isGPU" class="arch">GPU</div>
    </div>
    <div class="main">
      <div class="left">
        <div class="column">
          <div class="subtitle">服务模型</div>
          <div class="content scene">
            {{ businessSceneText }}
          </div>
        </div>
        <div class="column">
          <div class="subtitle">调度编排</div>
          <div class="content">
            {{ scheduleStrategyText }}
          </div>
        </div>
        <div class="column">
          <div class="subtitle">弹性扩缩</div>
          <div class="content">
            {{ scaleStrategyText }}
          </div>
        </div>
      </div>
      <div class="right">
        <div
          v-for="(key, index) in stageKes"
          :key="index"
          :class="['stage', index === 3 ? 'last' : '']"
        >
          <div class="top">
            <div
              :class="[
                'order',
                stageInfo.currentStage >= index + 1 ? 'active' : '',
              ]"
            >
              {{ index + 1 }}
            </div>
            <div
              :class="[
                'content',
                stageInfo.currentStage >= index + 1 ? 'active' : '',
              ]"
            >
              步骤 {{ index + 1 }}
            </div>
            <div v-if="index < 3" class="line">
              <div class="default"></div>
              <div
                v-if="stageInfo.currentStage >= index + 1"
                :class="[
                  'loading',
                  stageInfo[key].stageStatus === 3
                    ? 'completed'
                    : stageInfo[key].stageStatus === 2
                      ? 'error'
                      : '',
                ]"
              ></div>
              <div v-if="stageInfo[key].stageStatus === 2" class="error2">
                <img
                  class="icon"
                  src="@/assets/imgs/intelligent-scheduling/icon_error.png"
                  alt=""
                />
                <i class="el-icon-error" style="color: #f66173"></i>
              </div>
            </div>
          </div>
          <div
            :class="[
              'name',
              stageInfo[key].stageStatus === 1 ||
                stageInfo.currentStage === index + 1
                ? 'loading'
                : stageInfo[key].stageStatus === 3
                  ? 'success'
                  : stageInfo[key].stageStatus === 2
                    ? 'error'
                    : '',
            ]"
          >
            <img
              class="icon"
              :src="getStageStatusIcon(stageInfo[key].stageStatus)"
              alt=""
            />{{ stageInfo[key].title }}
          </div>
          <div v-if="stageInfo[key].stageStatus > 0" class="progress">
            <div class="bar">
              <div
                class="light"
                :style="{
                  width:
                    Math.round(
                      (Math.min(
                        stageInfo[key].steps.length,
                        stageInfo[key].stepTotal
                      ) *
                        100) /
                        stageInfo[key].stepTotal
                    ) + '%',
                }"
              ></div>
            </div>
            <div class="text">
              {{ stageInfo[key].steps.length }}/{{ stageInfo[key].stepTotal }}
            </div>
          </div>
          <div
            v-for="(step, stepIndex) in stageInfo[key].steps"
            :key="stepIndex"
            class="step"
          >
            <div class="step-detail">
              <img
                class="icon"
                alt=""
                :src="
                  step.success
                    ? require('@/assets/imgs/intelligent-scheduling/icon_status_complete.png')
                    : require('@/assets/imgs/intelligent-scheduling/icon_status_error.png')
                "
              />
              <div class="text">
                {{ step.detailType }}
                {{ step.success ? step.message : step.errorMsg }}
              </div>
            </div>
            <template
              v-if="Array.isArray(step.extraInfo) && step.extraInfo.length > 0"
            >
              <div
                v-for="(extraInfo, eIndex) in step.extraInfo"
                :key="eIndex"
                class="extraInfo"
              >
                <div v-if="extraInfo.vmName" class="info-item">
                  <span class="lname">节点名称</span><span class="value first">{{ extraInfo.vmName }}</span><span class="lname">节点规格</span><span
                    class="value"
                  >{{ extraInfo.cpu }}C{{ extraInfo.memory }}G</span>
                  <div v-if="isGPU">
                    <span class="lname">显卡规格</span><span class="value">{{ extraInfo.gpuFlavor }}</span>
                  </div>
                </div>
                <div v-if="extraInfo.providerName" class="info-item">
                  <span class="lname">云商名称</span><span class="value first">{{ extraInfo.providerName }}</span><span class="lname">集群名称</span><span class="value">{{ extraInfo.name }}</span>
                </div>
              </div>
            </template>
          </div>
        </div>
        <div class="status">
          <el-button
            v-if="stageInfo.svcStatus == 1"
            type="primary"
            size="mini"
            :loading="true"
          >部署中</el-button>
          <el-button
            v-else-if="stageInfo.svcStatus == 2"
            type="primary"
            size="mini"
            :loading="retryLoading"
            @click="retryDeploy(microService.svcId)"
          >重试</el-button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { GPU_BUSINESS_SCENE, STRATEGY_SCHEDULE_V2 } from '@/utils/cnap/constant'
import { retryServiceDeploy } from '@/api/cnap/app-service'

export default {
  name: 'ServiceDeployment',
  components: {},
  props: {
    // 微服务
    microService: {
      type: Object,
      default: () => {}
    },
    stageInfo: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    return {
      retryLoading: false,
      stageKes: ['firstStages', 'secondStages', 'thirdStages', 'fourthStages']
    }
  },
  computed: {
    /**
     * @description: 是GPU
     * @return {*}
     */
    isGPU() {
      const scheduleStrategy = this.microService.scheduleStrategy
      return (
        scheduleStrategy &&
        scheduleStrategy.businessScene &&
        scheduleStrategy.businessScene.svcType === GPU_BUSINESS_SCENE
      )
    },
    /**
     * @description: 业务场景文字
     * @return {*}
     */
    businessSceneText() {
      if (
        this.microService.scheduleStrategy &&
        this.microService.scheduleStrategy.businessScene &&
        this.microService.scheduleStrategy.businessScene.svcCategory
      ) {
        const businessScene = this.microService.scheduleStrategy.businessScene
        return businessScene.svcCategory + ' - ' + businessScene.svcType
      }
      return ''
    },
    /**
     * @description: 调度策略文字
     * @return {*}
     */
    scheduleStrategyText() {
      const arr = []
      if (this.microService.scheduleStrategy) {
        STRATEGY_SCHEDULE_V2.forEach((strategy) => {
          const strategyKey = strategy.value
          if (
            this.microService.scheduleStrategy[strategyKey] &&
            this.microService.scheduleStrategy[strategyKey].policy
          ) {
            arr.push(
              this.microService.scheduleStrategy[strategyKey].policy +
                ' ' +
                this.microService.scheduleStrategy[strategyKey].percent +
                '%'
            )
          }
        })
      }
      return arr.length === 0 ? '无' : arr.join(' | ')
    },
    /**
     * @description: 扩缩容策略
     * @return {*}
     */
    scaleStrategyText() {
      const arr = []
      if (Array.isArray(this.microService.scaleStrategy)) {
        this.microService.scaleStrategy.forEach((element) => {
          if (element.strategyName !== '不配置') {
            arr.push(element.strategyName)
          }
        })
      }
      return arr.length === 0 ? '无扩缩容' : arr.join(' / ')
    }
  },
  destroyed() {},
  created() {},
  methods: {
    /**
     * @description: 获取步骤状态 3-成功 2-错误 1-等待
     * @param {*} stage
     * @return {*}
     */
    getStageStatus(stage) {
      return stage && stage.success ? 3 : stage && !stage.success ? 2 : 1
    },
    /**
     * @description: 获取步骤状态图标
     * @param {*} stage
     * @return {*}
     */
    getStageStatusIcon(stageStatus) {
      if (stageStatus === 3) {
        return require('@/assets/imgs/intelligent-scheduling/icon_status_complete.png')
      } else if (stageStatus === 2) {
        return require('@/assets/imgs/intelligent-scheduling/icon_status_error.png')
      } else if (stageStatus === 1) {
        return require('@/assets/imgs/intelligent-scheduling/icon_status_loading.png')
      }
      return require('@/assets/imgs/intelligent-scheduling/icon_status_waiting.png')
    },
    /**
     * @description: 重试
     * @param {*} svcId
     * @return {*}
     */
    retryDeploy(svcId) {
      this.retryLoading = true
      // 请求
      retryServiceDeploy(svcId)
        .then((res) => {
          this.$emit('retry-success') // 抛出事件
        })
        .finally(() => {
          this.retryLoading = false
        })
    }
  }
}
</script>

<style lang="less" scoped>
@import "@/assets/css/common.less";
.service-deployment-ctn {
  min-height: 285px;
  background: #ffffff;
  box-shadow: 0px 0px 5px 0px rgba(217, 213, 234, 0.5);
  border-radius: 4px;
  border: 1px solid #e3e3e3;
  box-sizing: border-box;
  margin-bottom: 10px;

  .title {
    box-sizing: border-box;
    height: 42px;
    line-height: 42px;
    background: #0091ff;
    border-radius: 4px 4px 0px 0px;
    padding-left: 19px;
    .textStyle(16px, 600, #FFFFFF);
    .arch {
      margin-left: 15px;
      display: inline-block;
      padding: 0 10px;
      box-sizing: border-box;
      height: 24px;
      line-height: 22px;
      background: rgba(255, 255, 255, 0.8);
      border-radius: 12px;
      border: 1px solid #027dec;
      .textStyle(14px, 500, #027dec);
    }
  }

  .main {
    min-height: 243px;
    display: flex;
    flex-direction: row;
    .left {
      width: 265px;
      background: #f8f8f8;
      border-radius: 0px 0px 4px 0px;
      box-sizing: border-box;
      padding: 0 15px 0 20px;
      display: flex;
      flex-direction: column;
      justify-content: center;
      .column {
        display: flex;
        justify-content: flex-start;
        margin-top: 10px;
        &:first-child {
          margin-top: 0px;
        }
        .subtitle {
          width: 70px;
          text-align: right;
          height: 20px;
          line-height: 20px;
          .textStyle(14px, 400, #C3C3C3);
          flex-shrink: 0;
        }
        .content {
          margin-left: 20px;
          flex: 1;
          line-height: 20px;
          .textStyle(14px, 400, #4a4a4a);
          &.scene {
            color: #0091ff;
          }
        }
      }
    }
    .right {
      min-width: 1000px;
      flex: 1;
      box-sizing: border-box;
      padding: 30px 20px 20px 20px;
      display: flex;
      align-items: center;
      position: relative;

      .stage {
        flex: 1;
        height: 100%;
        &.last {
          flex: none;
          .name {
            min-width: 220px;
          }
        }
        .top {
          display: flex;
          flex-direction: row;
          align-items: center;

          .order {
            width: 18px;
            height: 18px;
            background: #ffffff;
            text-align: center;
            border: 1px solid #c3c3c3;
            border-radius: 50%;
            box-sizing: border-box;
            display: flex;
            justify-content: center;
            align-items: center;
            .textStyle(13px, 400, #C3C3C3);

            &.active {
              background: #0091ff;
              border: none;
              color: #ffffff;
            }
          }
          .content {
            margin: 0 15px 0 5px;
            .textStyle(14px, 500, #B9B9B9);
            line-height: 20px;
            &.active {
              .textStyle(14px, 500, #262626);
            }
          }
          .line {
            margin-right: 20px;
            flex: 1;
            position: relative;
            .default {
              position: absolute;
              left: 0;
              top: 0;
              right: 0;
              height: 0px;
              border-bottom: 1px dotted #d8d8d8;
            }
            .loading {
              position: absolute;
              left: 0;
              top: 0;
              width: 50%;
              height: 2px;
              background: linear-gradient(
                270deg,
                rgba(0, 196, 255, 1) 0%,
                rgba(0, 145, 255, 1) 100%
              );
              z-index: 2;
              &.completed {
                width: 100%;
                height: 2px;
              }
              &.error {
                height: 2px;
                background: linear-gradient(
                  270deg,
                  rgba(255, 0, 198, 1) 0%,
                  rgba(246, 97, 115, 1) 100%
                );
              }
            }
            .error2 {
              z-index: 3;
              position: absolute;
              left: 50%;
              transform: translateX(-50%);
              bottom: -7px;
              display: flex;
              flex-direction: column;
              align-items: center;
              .icon {
                width: 50px;
                height: 23px;
              }
            }
          }
        }
        .name {
          margin-top: 10px;
          display: flex;
          align-items: center;
          .textStyle(14px, 400, #B9B9B9);
          line-height: 20px;
          &.loading {
            color: #262626;
          }
          &.success {
            color: #6dd400;
          }
          &.error {
            color: #f66173;
          }
          .icon {
            width: 14px;
            height: 14px;
            margin-right: 5px;
          }
        }
        .progress {
          margin-top: 10px;
          display: flex;
          align-items: center;
          .bar {
            width: 200px;
            height: 8px;
            background: #f3f3f3;
            border-radius: 6px;
            position: relative;
            .light {
              position: absolute;
              border-radius: 6px;
              height: 8px;
              width: 0%;
              background: linear-gradient(90deg, #00eaff 0%, #009fff 100%);
            }
          }
          .text {
            .textStyle(12px, 400, #C3C3C3);
            margin-left: 6px;
          }
        }
        .step {
          margin-top: 8px;
          .step-detail {
            display: flex;
            flex-direction: row;
            align-items: center;
            .icon {
              width: 14px;
              height: 14px;
            }
            .text {
              .textStyle(12px, 400, #4a4a4a);
              margin-left: 5px;
            }
          }
          .extraInfo {
            margin-top: 5px;
            padding: 2px 10px;
            background: #f3f3f3;
            border-radius: 1px;
            display: inline-block;
            .info-item {
              // display: flex;
              // align-items: flex-start;
              // flex-wrap: wrap;
              .lname {
                .textStyle(12px, 400, #C3C3C3);
                line-height: 17px;
                flex-shrink: 0;
              }
              .value {
                .textStyle(12px, 400, #4a4a4a);
                line-height: 17px;
                margin-left: 10px;
                &.first {
                  margin-right: 20px;
                  flex-shrink: 0;
                }
              }
            }
          }
        }
      }
      .status {
        position: absolute;
        right: 20px;
        bottom: 20px;
      }
    }
  }
}
</style>
